package xyz.jfshare.netty.study.server.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import xyz.jfshare.netty.study.server.config.Config;
import xyz.jfshare.netty.study.server.entity.Friend;
import xyz.jfshare.netty.study.server.entity.Message;
import xyz.jfshare.netty.study.server.entity.User;
import xyz.jfshare.netty.study.server.service.FriendService;
import xyz.jfshare.netty.study.server.service.MessageService;
import xyz.jfshare.netty.study.server.service.UserService;
import xyz.jfshare.netty.study.server.util.StringUtil;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ChatServerHandler extends SimpleChannelInboundHandler<String> {

    private UserService userService;
    private FriendService friendService;
    private MessageService messageService;

    public ChatServerHandler(UserService userService, FriendService friendService, MessageService messageService) {
        this.userService = userService;
        this.friendService = friendService;
        this.messageService = messageService;
    }

    private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    private static Map<String,Channel> channelMap = new HashMap<>();

    private static Map<String,Channel> allOnlineUser = new HashMap<>();

    @Override
    @Transactional(rollbackFor = Exception.class)
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        Channel channel = ctx.channel();
        //是否为命令
        if (msg.startsWith(Config.COMMAND_PREFIX)){
            //截取Command ==>前缀
            msg = msg.replace(Config.COMMAND_PREFIX,"").trim();
            //是否为登录命令
            if (msg.startsWith(Config.LOGIN_COMMAND)) {
                //登录
                login(msg, channel);
            //是否为选择模式命令
            }else if (msg.startsWith(Config.CHOOSE_CHANNEL_COMMAND)){
                //选择进入聊天室还是和好友聊天
                chooseModel(msg,channel);
            //是否为注册命令
            }else if (msg.startsWith(Config.REGISTER_COMMAND)) {
                //注册
                register(msg, channel);
            //是否为显示陌生人列表命令
            }else if (msg.startsWith(Config.SHOW_NOT_FRIEND_COMMAND)) {
                showNotFriend(msg,channel);
            //是否为显示好友列表命令
            }else if (msg.startsWith(Config.SHOW_FRIEND_COMMAND)){
                showFriend(msg,channel);
            //是否为添加好友命令
            }else if (msg.startsWith(Config.ADD_FRIEND_COMMAND)){
                addFriend(msg,channel);
            //是否为选择窗口命令
            }else if (msg.startsWith(Config.CHOOSE_WINDOW_COMMAND)){
                chooseWindow(msg);
            //是否为获取系统消息命令
            }else if (msg.startsWith(Config.GET_SYSTEM_MSG_COMMAND)) {
                getSystemMsg(msg, channel);
            //是否为处理系统消息命令
            }else if (msg.startsWith(Config.HANDLER_SYSTEM_MSG_COMMAND)){
                handlerSystemMsg(msg);
            //是否为获取聊天记录命令
            }else if (msg.startsWith(Config.GET_USER_MSG_COMMAND)){
                msg = msg.replace(Config.GET_USER_MSG_COMMAND,"").trim();
                Set<String> info = StringUtil.split(msg, ",");
                int userId = 0,toId = 0;
                int id = 0;
                for (String str : info) {
                    if (str.startsWith("userId=")) {
                        str = str.replace("userId=", "");
                        userId = Integer.parseInt(str);
                    } else if (str.startsWith("toId=")) {
                        str = str.replace("toId=", "");
                        toId = Integer.parseInt(str);
                    }
                }

                List<Message> chatRecord = messageService.getChatRecord(userId, toId);
                if (!chatRecord.isEmpty()){
                    String json = JSONObject.toJSONString(chatRecord);
                    channel.writeAndFlush(Config.COMMAND_PREFIX + Config.GET_USER_MSG_COMMAND + json + '\n');
                }else {
                    channel.writeAndFlush(Config.COMMAND_PREFIX + Config.GET_USER_MSG_COMMAND + "null\n");
                }
            //是否为退出命令
            }else if (msg.startsWith(Config.LOGOUT_COMMAND)){
                logout(channel);
            }
        }
        //是否为消息
        else if (msg.startsWith(Config.MESSAGE_PREFIX)){
            //如果信息开头为Message ==> ，去掉
            msg = msg.replace(Config.MESSAGE_PREFIX,"").trim();
            //判断是聊天室信息还是个人信息
            if (msg.contains(Config.MESSAGE_PERSON)){
                sendPersonMessage(msg,channel);
            }else if (msg.contains(Config.MESSAGE_GROUP)){
                sendChatRoomMessage(msg,channel);
            }
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        logout(channel);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    private void login(String msg,Channel channel){
        msg = msg.replace(Config.LOGIN_COMMAND, "").trim();

        Set<String> info = StringUtil.split(msg, ",");
        String username="",password="";
        if (!info.isEmpty()){
            for (String s : info) {
                s = s.trim();
                if (s.startsWith("username=")){
                    username = s.replace("username=","");
                }else if (s.startsWith("password=")){
                    password = s.replace("password=","");
                }
            }
        }
        String res = userService.login(username, password);
        if (res.startsWith("success-")){
            String json = res.replace("success-","");
            User user = JSON.parseObject(json, User.class);
            allOnlineUser.put(user.getNickName(),channel);
        }
        channel.writeAndFlush(Config.COMMAND_PREFIX+Config.LOGIN_COMMAND+res+'\n');
    }

    private void register(String msg,Channel channel){
        msg = msg.replace(Config.REGISTER_COMMAND, "").trim();

        Set<String> info = StringUtil.split(msg, ",");
        String username="",password="",rePassword = "",nickName = "";
        if (!info.isEmpty()){
            for (String s : info) {
                s = s.trim();
                if (s.startsWith("username=")){
                    username = s.replace("username=","");
                }else if (s.startsWith("password=")){
                    password = s.replace("password=","");
                }else if (s.startsWith("rePassword=")){
                    rePassword = s.replace("rePassword=","");
                }else if (s.startsWith("nickName=")){
                    nickName = s.replace("nickName=","");
                }
            }
            String res = userService.register(username, password, rePassword, nickName);
            channel.writeAndFlush(Config.COMMAND_PREFIX + Config.REGISTER_COMMAND + res + '\n');
        }
    }

    private void chooseModel(String msg,Channel channel){
        if (msg.startsWith(Config.CHOOSE_CHAT_ROOM)){
            String nickName = msg.replace(Config.CHOOSE_CHAT_ROOM, "").trim();
            channelGroup.writeAndFlush(Config.MESSAGE_PREFIX + nickName + "加入了聊天室\n");
            channelGroup.add(channel);
            allOnlineUser.put(nickName,channel);
        }else if (msg.startsWith(Config.CHOOSE_SINGLE_CHAT)){
            String nickName = msg.replace(Config.CHOOSE_SINGLE_CHAT, "").trim();
            channelMap.put(nickName,channel);
            allOnlineUser.put(nickName,channel);
        }
    }

    private void logout(Channel channel){
        String key = "";
        for (Map.Entry<String,Channel> entry : allOnlineUser.entrySet()){
            if (entry.getValue() == channel){
                key = entry.getKey();
                User user = userService.getByNickName(key);
                if (user!=null){
                    user.setStatus(Config.OFFLINE);
                    user.setWindow(0);
                    user.setUpdateTime(null);
                    userService.updateById(user);
                }
            }
        }
        allOnlineUser.remove(key);
        channelMap.remove(key);
    }

    private void sendPersonMessage(String msg,Channel channel){
        //如果信息开头为person-> ，去掉
        msg = msg.replace(Config.MESSAGE_PERSON,"").trim();
        //将msg分割成Set
        Set<String> info = StringUtil.split(msg, Config.MESSAGE_REGEX);
        String nickName = "",message = "",to = "";
        int id = 0;
        for (String str : info) {
            if (str.startsWith("nickName=")){
                nickName = str.replace("nickName=","");
            }else if (str.startsWith("to=")) {
                to = str.replace("to=","");
            }else if (str.startsWith("id=")) {
                str = str.replace("id=","");
                id = Integer.parseInt(str);
            }else {
                message = str;
            }
        }
        User toUser = userService.getByNickName(to);
        if (toUser == null){
            channel.writeAndFlush(Config.MESSAGE_PREFIX + "[服务器] : 收信用户不存在"  + '\n');
        }else if (StringUtils.isEmpty(message)){
            //判断消息是否为空
            channel.writeAndFlush(Config.MESSAGE_PREFIX + "[服务器] : 没有输入消息"  + '\n');
        }else {
            //nickName:发信人昵称
            String finalMessage = '[' +nickName +']' + message;
            int toId = userService.getByNickName(to).getId();
            Message m = new Message();
            m.setType(1);
            m.setFromId(id);
            m.setToId(toId);
            m.setContent(finalMessage);
            if (toUser.getWindow().equals(id)) {
                //判断收信用户是否处于发信人的聊天窗口，如果在则直接发送，如果不在，则先存数据库，等进入再打印
                m.setIsRead(1);
                String finalTo = to;
                channelMap.forEach((s, ch) -> {
                    if (s.equals(finalTo)) {
                        ch.writeAndFlush(Config.MESSAGE_PREFIX + finalMessage + "\n");
                    }
                });
            }else {
                //发送系统消息前，先判断是否已经有这个消息
                String content = Config.MESSAGE_CONTENT_NOT_READ + "昵称:" + nickName + "-向您发送了新的消息!";
                Message one = messageService.getOne(
                        new QueryWrapper<Message>()
                                .eq("is_delete",0)
                                .eq("is_read",0)
                                .eq("to_id",toId)
                                .eq("content",content)
                );

                if (one == null) {
                    Message systemMsg= new Message();
                    //发送系统消息
                    systemMsg.setContent(content);
                    systemMsg.setType(2);
                    systemMsg.setFromId(0);
                    systemMsg.setToId(toId);
                    messageService.insert(systemMsg);
                }
            }
            messageService.insert(m);
        }
    }

    private void sendChatRoomMessage(String msg,Channel channel){
        msg = msg.replace(Config.MESSAGE_GROUP,"").trim();
        Set<String> info = StringUtil.split(msg, Config.MESSAGE_REGEX);
        String nickName = "",message = "";
        for (String str : info) {
            if (str.contains("nickName=")){
                nickName = str.replace("nickName=","").trim();
            }else {
                message = str;
            }
        }
        if (!StringUtils.isEmpty(message)){
            channelGroup.writeAndFlush(Config.MESSAGE_PREFIX + '[' + nickName + "] : " + message + '\n');
        }
    }

    private void showNotFriend(String msg,Channel channel){
        msg = msg.replace(Config.SHOW_NOT_FRIEND_COMMAND, "").trim();
        msg = msg.replace("id=", "");
        int userId = Integer.parseInt(msg);
        List<User> friends = friendService.getNotFriendByUserId(userId);
        if (friends.isEmpty()) {
            channel.writeAndFlush(Config.COMMAND_PREFIX + Config.SHOW_NOT_FRIEND_COMMAND + "null\n");
            return;
        }
        String json = JSONObject.toJSONString(friends);
        channel.writeAndFlush(Config.COMMAND_PREFIX + Config.SHOW_NOT_FRIEND_COMMAND + json + '\n');
    }

    private void showFriend(String msg,Channel channel){
        msg = msg.replace(Config.SHOW_FRIEND_COMMAND,"").trim();
        msg = msg.replace("id=", "");
        int userId = Integer.parseInt(msg);
        List<User> friends = friendService.getFriendByUserId(userId);
        if (friends.isEmpty()){
            channel.writeAndFlush(Config.COMMAND_PREFIX + Config.SHOW_FRIEND_COMMAND +"null\n");
            return;
        }
        String json = JSONObject.toJSONString(friends);
        channel.writeAndFlush(Config.COMMAND_PREFIX + Config.SHOW_FRIEND_COMMAND + json + '\n');
    }

    private void addFriend(String msg,Channel channel){
        msg = msg.replace(Config.ADD_FRIEND_COMMAND, "").trim();
        Set<String> info = StringUtil.split(msg, ",");
        String nickName = "";
        int id = 0;
        for (String str : info) {
            if (str.startsWith("id=")){
                str = str.replace("id=","");
                id = Integer.parseInt(str);
            }else if (str.startsWith("nickName=")){
                nickName = str.replace("nickName=","");
            }
        }
        //发送系统消息
        Message message = new Message();
        message.setContent(Config.MESSAGE_CONTENT_FRIEND_APP + "昵称:" + nickName +"-请求添加您为好友!");
        message.setToId(id);
        message.setFromId(0);
        message.setType(2);
        messageService.insert(message);
    }

    private void chooseWindow(String msg){
        msg = msg.replace(Config.CHOOSE_WINDOW_COMMAND,"").trim();
        Set<String> info = StringUtil.split(msg, ",");
        int window = 0,id = 0;
        for (String str : info) {
            if (str.startsWith("id=")) {
                str = str.replace("id=", "");
                id = Integer.parseInt(str);
            }else if (str.startsWith("window=")) {
                str = str.replace("window=","");
                window = Integer.parseInt(str);
            }
        }
        userService.setWindow(id,window);
    }

    private void getSystemMsg(String msg,Channel channel){
        msg = msg.replace(Config.GET_SYSTEM_MSG_COMMAND,"").trim();
        int id = Integer.parseInt(msg);
        List<Message> list = messageService.getSystemMsgByUserId(id);
        String json;
        if (list.isEmpty()){
            json = "null";
        }else {
            json = JSONObject.toJSONString(list);
        }
        channel.writeAndFlush(Config.COMMAND_PREFIX + Config.GET_SYSTEM_MSG_COMMAND + json + '\n');
    }

    private void handlerSystemMsg(String msg){
        msg = msg.replace(Config.HANDLER_SYSTEM_MSG_COMMAND,"").trim();
        Set<String> info = StringUtil.split(msg, ",");
        int messageId = 0,id = 0;
        String key = "",nickName = "";
        for (String str : info) {
            if (str.startsWith("message_id=")){
                str = str.replace("message_id=","").trim();
                messageId = Integer.parseInt(str);
            }else if (str.startsWith("key=")){
                str = str.replace("key=","").trim();
                key = str;
            }else if (str.startsWith("nickName=")){
                str = str.replace("nickName=","").trim();
                nickName = str;
            }else if (str.startsWith("userId=")){
                str = str.replace("userId=","").trim();
                id = Integer.parseInt(str);
            }
        }
        Message message = messageService.getById(messageId);
        message.setIsRead(1);
        message.setUpdateTime(null);
        messageService.updateById(message);
        if (!nickName.equals("")){
            User appUser = userService.getByNickName(nickName);
            if (key.equals("y") || key.equals("Y")){
                if (appUser != null && id != 0){
                    Friend friend = new Friend();
                    friend.setUserId(id);
                    friend.setFriendId(appUser.getId());
                    friendService.insert(friend);
                    friend = new Friend();
                    friend.setUserId(appUser.getId());
                    friend.setFriendId(id);
                    friendService.insert(friend);
                }
            }
        }
    }
}
